/**
    ******************************************************************************
    * @file    main.c 
    * @author  18408107475@163.com
    * @version v1.0
    * @date    2025/04/05
    * @brief   STM32F10x系列呼吸灯控制程序
    * @details 
    * 功能特性：
    * - 使用SysTick定时器实现精确延时
    * - 通过PWM方式控制LED亮度渐变
    * - 支持微秒、毫秒、秒级延时函数
    * 
    * 硬件连接：
    * - PB5连接LED1，低电平点亮
    * - PE5连接LED2，低电平点亮
    * - 使用外部9MHz时钟源
    * 
    * 注意事项：
    * - 延时函数最大时长受24位计数器限制
    * - 呼吸灯周期为2ms，频率500Hz
    * - 不适用于实时性要求高的中断服务程序
    ******************************************************************************
**/

/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f10x.h"  // STM32标准外设库，包含所有外设寄存器定义和配置函数

/* 函数声明 ------------------------------------------------------------------*/
void LED_STD_Config(void);     // LED GPIO初始化配置函数
void Delay_us(uint32_t xus);   // 微秒级延时函数
void Delay_ms(uint32_t xms);   // 毫秒级延时函数
void Delay_s(uint32_t xs);     // 秒级延时函数

/* 全局变量 ------------------------------------------------------------------*/
// 当前无全局变量定义

/**
    ******************************************************************************
    * @brief  LED GPIO初始化配置
    * @param  无
    * @retval 无
    * @detail 
    * 功能描述：
    * - 配置PB5和PE5为推挽输出模式，用于驱动LED
    * - 设置GPIO输出速度为50MHz
    * - 初始化LED状态为熄灭
    * 
    * 硬件连接：
    * - PB5连接LED1，低电平点亮
    * - PE5连接LED2，低电平点亮
    * 
    * 工作流程：
    * 1. 使能GPIOB和GPIOE时钟
    * 2. 配置PB5和PE5为推挽输出
    * 3. 设置初始输出高电平
    ******************************************************************************
**/
void LED_STD_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;  // GPIO初始化结构体
    
    /* 开启GPIOB和GPIOE时钟（APB2总线） */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);

    /* 配置PB5引脚 */
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5;        // 选择引脚5
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  // 高速模式可改善边沿特性
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;  // 推挽输出直接驱动LED
    GPIO_Init(GPIOB, &GPIO_InitStructure);            // 初始化GPIOB

    /* 配置PE5引脚（复用同一结构体） */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;         // 选择引脚5
    GPIO_Init(GPIOE, &GPIO_InitStructure);            // 初始化GPIOE

    /* 设置初始状态 */
    GPIO_SetBits(GPIOB, GPIO_Pin_5);   // PB5输出高电平，LED1初始熄灭
    GPIO_SetBits(GPIOE, GPIO_Pin_5);   // PE5输出高电平，LED2初始熄灭
}

/**
    ******************************************************************************
    * @brief  微秒级延时函数
    * @param  xus 延时时长，范围：0 ~ 1864134 us (约1.86秒)
    * @note   使用外部时钟STCLK —— 9MHz
    * @retval 无
    * @detail 
    * 工作原理：
    * - SysTick为24位递减计数器
    * - 计算公式：LOAD = (时钟频率/1000000) * xus - 1
    * - 9MHz时钟时，1us需要9个时钟周期
    * 
    * 工作流程：
    * 1. 关闭SysTick定时器
    * 2. 设置重装载值
    * 3. 清除当前计数值
    * 4. 启动定时器
    * 5. 等待计数完成标志
    * 6. 关闭定时器
    * 
    * 注意事项：
    * - 最大延时受24位计数器限制(2^24/9 ≈ 1864134us)
    * - 不适用于在中断服务程序中调用
    * - 实际延时会有几个时钟周期的函数调用开销
    ******************************************************************************
**/
void Delay_us(uint32_t xus)
{
    SysTick->CTRL = 0;                      // 关闭SysTick定时器
    SysTick->LOAD = (9 * xus) - 1;          // 设置重装载值(9MHz时钟下)
    SysTick->VAL = 0x00;                    // 清除当前计数值
    SysTick->CTRL = 0x00000001;             // 启用SysTick（使用STCLK时钟源）
    while(!(SysTick->CTRL & 0x00010000));   // 等待COUNTFLAG置位（计数完成）
    SysTick->CTRL = 0;                      // 关闭SysTick定时器
}

/**
    ******************************************************************************
    * @brief  毫秒级延时函数
    * @param  xms 延时时长，范围：0~1864 ms
    * @note   基于Delay_us函数实现
    * @retval 无
    * @detail 
    * 实现原理：
    * - 通过循环调用Delay_us(1000)实现毫秒延时
    * 
    * 注意事项：
    * - 实际最大延时受Delay_us函数限制
    * - 存在函数调用开销，精度略低于直接使用SysTick
    * - 长时间延时会影响系统实时性
    ******************************************************************************
**/
void Delay_ms(uint32_t xms)
{
    while(xms--)  // 循环xms次
    {
        Delay_us(1000);  // 每次延时1000us(1ms)
    }
}

/**
    ******************************************************************************
    * @brief  秒级延时函数
    * @param  xs 延时时长，范围：0~1 s
    * @note   基于Delay_ms函数实现
    * @retval 无
    * @detail 
    * 实现原理：
    * - 通过循环调用Delay_ms(1000)实现秒级延时
    * 
    * 注意事项：
    * - 适用于非精确长延时场景
    * - 长时间阻塞式延时会严重影响系统实时性
    * - 实际应用中建议使用定时器中断实现非阻塞延时
    ******************************************************************************
**/
void Delay_s(uint32_t xs)
{
    while(xs--)  // 循环xs次
    {
        Delay_ms(1000);  // 每次延时1000ms(1s)
    }
} 

/**
    ******************************************************************************
    * @brief  主函数
    * @param  无
    * @retval int 程序返回值（实际不会返回）
    * @detail 
    * 功能描述：
    * - 实现LED呼吸灯效果
    * - 通过改变PWM占空比实现亮度渐变
    * 
    * 工作流程：
    * 1. 初始化LED GPIO
    * 2. 进入无限循环：
    *    a. 从1到1000逐渐增加LED点亮时间
    *    b. 从1000到1逐渐减少LED点亮时间
    * 
    * 技术参数：
    * - PWM周期：2000us (2ms)
    * - PWM频率：500Hz
    * - 亮度分辨率：1000级
    * 
    * 硬件连接：
    * - 使用PB5控制LED1
    ******************************************************************************
**/
int main(void)
{
    LED_STD_Config();  // 初始化LED GPIO
    int i;  // 循环变量，用于控制亮度递增
    int x;  // 循环变量，用于控制亮度递减

    while(1)  // 主循环
    {
        // 亮度递增阶段：从暗到亮
        for(i=1; i<=1000; i++){
            GPIO_ResetBits(GPIOB, GPIO_Pin_5);  // LED点亮
            Delay_us(i);                        // 延时i微秒
            GPIO_SetBits(GPIOB, GPIO_Pin_5);    // LED熄灭
            Delay_us(2000-i);                   // 延时(2000-i)微秒
        }
        
        // 亮度递减阶段：从亮到暗
        for(x=1000; x>=1; x--){
            GPIO_ResetBits(GPIOB, GPIO_Pin_5);  // LED点亮
            Delay_us(x);                        // 延时x微秒
            GPIO_SetBits(GPIOB, GPIO_Pin_5);    // LED熄灭
            Delay_us(2000-x);                   // 延时(2000-x)微秒
        }
    }
}

/*************************************END OF FILE**************************************/
